#include "../include/CHorizontalEnemyBehaviour.h"
#include "../include/CDefaultShotBehaviour.h"
#include "../include/CBombShotBehaviour.h"
#include "../include/CSprite.h"
#include "../include/CSpriteAnimation.h"

#include <SDL/SDL.h>
#include <time.h>
#include <math.h>

//**************************
//Description : Constructor
//Parameters : Value for m_iX, m_iY,
//              m_iSpeedX, m_iSpeedY,
//              m_iWidth, m_iHeight,
//              the ratio for the collision box
//              the type of colision
//              m_iLives
//              m_iNbPoints
//Note : None
//**************************
CHorizontalEnemyBehaviour::CHorizontalEnemyBehaviour(int _iX, int _iY,
                                                int _iSpeedX, int _iSpeedY,
                                                int _iWidth, int _iHeight,
                                                float _fRatioW, float _fRatioH,
                                                TYPE_COLLISION _iTypeCollision,
                                                int _iLives,
                                                int _iNbPoints)
    : CDefaultEnemyBehaviour(_iX, _iY,
                                _iSpeedX, _iSpeedY,
                                _iWidth, _iHeight,
                                _fRatioW, _fRatioW,
                                _iTypeCollision,
                                _iLives,
                                _iNbPoints),
    m_iDistanceOnY(-1)
{
    //if the X value is lower than GAME_WINDOW_X or higher than GAME_WINDOW_X + GAME_WINDOW_WIDTH
    //we have to make it correspond to the left or to the right, juste before GAME_WINDOW_X or after GAME_WINDOW_X + GAME_WINDOW_WIDTH
    if ( (m_iX + m_iWidth/2) < GAME_WINDOW_X )
        m_iX = GAME_WINDOW_X - m_iWidth/2;

    if ( (m_iX - m_iWidth/2) > (GAME_WINDOW_X + GAME_WINDOW_WIDTH) )
        m_iX = GAME_WINDOW_X + GAME_WINDOW_WIDTH + m_iWidth/2;

    //this enemy only shoot primary shot
    m_iPrimaryShot = DEFAULTSHOT;
    m_iSecondaryShot = -1;

    m_iTimeBetweenPrimaryShot = 800;
    m_iTimeBetweenSecondaryShot = -1;

    srand((unsigned int)time(NULL));
}

//**************************
//Description : Copy Constructor
//Parameters : A CHorizontalEnemyBehaviour
//Note : None
//**************************
CHorizontalEnemyBehaviour::CHorizontalEnemyBehaviour(CHorizontalEnemyBehaviour & _HorizontalEnemy)
    : CDefaultEnemyBehaviour(_HorizontalEnemy)
{
}

//**************************
//Description : Destructor
//Parameters : None
//Note : None
//**************************
CHorizontalEnemyBehaviour::~CHorizontalEnemyBehaviour()
{
}

//**************************
//Description : The entity shoot
//Parameters : The tab of animations shot and the screen
//Return Value : True if the enemy has shot, otherwise false
//Note : Virtual because the way of shooting depends on the entity
//**************************
bool CHorizontalEnemyBehaviour::Shoot(CSpriteAnimation * _SpriteAnimationShot, SDL_Surface * _screen)
{
    if ( ( (Uint32)(m_lLastPrimaryShoot + m_iTimeBetweenPrimaryShot) < SDL_GetTicks() ) )
    {
        CDefaultShotBehaviour * Shot;

        switch ( m_iPrimaryShot )
        {
            case DEFAULTSHOT:
            {
                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                -1,
                                                -4,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                1,
                                                -4,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                -4,
                                                0,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                4,
                                                0,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                -1,
                                                4,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                Shot = new CDefaultShotBehaviour(m_iX,
                                                m_iY,
                                                1,
                                                4,
                                                _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );

                break;
            }
            case BOMB:
            {
                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                -1,
                                                -4,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                1,
                                                -4,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                -4,
                                                0,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                4,
                                                0,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                -1,
                                                4,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                Shot = new CBombShotBehaviour(m_iX,
                                                m_iY,
                                                1,
                                                4,
                                                _SpriteAnimationShot[BOMB].GetWidth(),
                                                _SpriteAnimationShot[BOMB].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[BOMB], _screen );

                m_vShots->push_back( Shot );

                break;
            }
            default:
            {
                Shot = new CDefaultShotBehaviour(m_iX, m_iY,
                                                    0, 4,
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetWidth(),
                                                    _SpriteAnimationShot[DEFAULTSHOT].GetHeight());

                Shot->SetSprite( &_SpriteAnimationShot[DEFAULTSHOT], _screen );

                m_vShots->push_back( Shot );
            }
        }

        m_lLastPrimaryShoot = SDL_GetTicks();

        return true;
    }
    else
        return false;
}

//**************************
//Description : Update the trajectory of the entity
//Parameters : None
//Return Value : None
//Note : Virtual because actions depends on the entity type
//**************************
void CHorizontalEnemyBehaviour::EntityTrajectory()
{
    //if we are at the top of the screen (beginning of the level),
    // we go down until
    //          we are in the screen
    //          we are on an y on which we can move on X
    if ( (m_iY - m_iHeight/2) < 0 )
    {
        m_iY += m_iSpeedY;
    }
    else
    {
        //if we don't have to move on y
        if ( m_iDistanceOnY <= 0 )
        {
            //we move it on X
            m_iX += m_iSpeedX;

            //if we are out of the screen, we have to go down
            if ( IsOutOfScreen() )
            {
                m_iDistanceOnY = rand() % MAX_DISTANCE_Y + 1;

                //if we are out of the screen on the left, our speed has to be positive
                //if we are out of the screen on the right, our speed has to be negative
                if ( ( ( (m_iX + m_iWidth/2) < GAME_WINDOW_X ) && m_iSpeedX < 0 )
                    || ( ( (m_iX - m_iWidth/2) > (GAME_WINDOW_X + GAME_WINDOW_WIDTH) ) && m_iSpeedX > 0 ) )
                    m_iSpeedX *= (-1);
            }
        }
        else
        {
            //if it is out of the screen we move it on Y until we do 0 to 300 pixels
            m_iY += m_iSpeedY;
            m_iDistanceOnY -= m_iSpeedY;
        }
    }
}
